package org.xx.armory.ofs;

import java.util.Collection;
import java.util.Date;
import java.util.Objects;
import java.util.Set;

import static java.util.Collections.unmodifiableCollection;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;
import static org.xx.armory.commons.Validators.greaterThan;
import static org.xx.armory.commons.Validators.greaterThanOrEqual;
import static org.xx.armory.commons.Validators.notBlank;
import static org.xx.armory.commons.Validators.notNull;
import static org.xx.armory.ofs.FileObjectUtils.hashFile;
import static org.xx.armory.ofs.FileObjectUtils.parseAttributes;

/**
 * 文件对象。
 */
public final class FileObject {
    private final long id;
    private final long objectId;
    private final long fileType;
    private final long parentId;
    private final String name;
    private final long size;
    private final Date lastModifiedTime;
    private final String description;
    private final byte[] brief;
    private final Set<FileAttribute> attributes;
    private final String hash;

    /**
     * 构造文件对象实例。
     *
     * @param id
     *         文件对象的ID
     * @param objectId
     *         关联对象的ID
     * @param fileType
     *         文件对象的类型
     * @param parentId
     *         上级目录对象的ID
     * @param name
     *         文件对象的名字
     * @param size
     *         文件对象的长度
     * @param lastModifiedTime
     *         文件对象的最后修改时间
     * @param description
     *         文件对象的描述
     * @param brief
     *         文件对象的摘要
     * @param attributes
     *         文件对象的属性
     * @param hash
     *         文件的Hash码，应当通过{@code id}和{@code name}计算得出，根目录的Hash码应当是空字符串。
     */
    public FileObject(
            long id,
            long objectId,
            long fileType,
            long parentId,
            String name,
            long size,
            Date lastModifiedTime,
            String description,
            byte[] brief,
            long attributes,
            String hash
    ) {
        this.id = greaterThanOrEqual(id, "id", 0L);
        this.objectId = greaterThan(objectId, "objectId", 0L);
        this.fileType = greaterThan(fileType, "fileType", 0L);
        this.parentId = greaterThanOrEqual(parentId, "parentId", 0L);
        this.name = notBlank(name, "name").trim();
        this.size = greaterThanOrEqual(size, "size", 0L);
        this.lastModifiedTime = notNull(lastModifiedTime, "lastModifiedTime");
        this.description = trimToEmpty(description);
        this.brief = brief;
        this.attributes = parseAttributes(attributes);
        this.hash = trimToEmpty(hash);
    }

    /**
     * 构造文件对象实例。
     *
     * @param id
     *         文件对象的ID
     * @param objectId
     *         关联对象的ID
     * @param fileType
     *         文件对象的类型
     * @param parentId
     *         上级目录对象的ID
     * @param name
     *         文件对象的名字
     * @param size
     *         文件对象的长度
     * @param lastModifiedTime
     *         文件对象的最后修改时间
     * @param description
     *         文件对象的描述
     * @param brief
     *         文件对象的摘要
     * @param attributes
     *         文件对象的属性
     */
    public FileObject(
            long id,
            long objectId,
            long fileType,
            long parentId,
            String name,
            long size,
            Date lastModifiedTime,
            String description,
            byte[] brief,
            long attributes
    ) {
        this(id, objectId, fileType, parentId, name, size, lastModifiedTime, description, brief, attributes,
             id > 0L ? hashFile(id, trimToEmpty(name)) : "");
    }

    /**
     * get ID
     * <p>文件对象的ID</p>
     *
     * @return value of ID
     */
    public final long getId() {
        return id;
    }

    /**
     * get OBJECT_ID
     * <p>关联对象的ID</p>
     *
     * @return value of OBJECT_ID
     */
    public final long getObjectId() {
        return objectId;
    }

    /**
     * get FILE_TYPE
     * <p>文件对象的类型</p>
     *
     * @return value of FILE_TYPE
     */
    public final long getFileType() {
        return fileType;
    }

    /**
     * get PARENT_ID
     * <p>上级目录对象的ID</p>
     *
     * @return value of PARENT_ID
     */
    public final long getParentId() {
        return parentId;
    }

    /**
     * get NAME
     * <p>文件对象的名字</p>
     *
     * @return value of NAME
     */
    public final String getName() {
        return name;
    }

    /**
     * get SIZE
     * <p>文件对象的长度</p>
     *
     * @return value of SIZE
     */
    public final long getSize() {
        return size;
    }

    /**
     * get LAST_MODIFIED_TIME
     * <p>文件对象的最后修改时间</p>
     *
     * @return value of LAST_MODIFIED_TIME
     */
    public final java.util.Date getLastModifiedTime() {
        return lastModifiedTime;
    }

    /**
     * get DESCRIPTION
     * <p>文件对象的描述</p>
     *
     * @return value of DESCRIPTION
     */
    public final String getDescription() {
        return description;
    }

    /**
     * get BRIEF
     * <p>文件对象的摘要</p>
     *
     * @return value of BRIEF
     */
    public final byte[] getBrief() {
        return brief;
    }

    /**
     * get ATTRS
     * <p>文件对象的属性</p>
     *
     * @return value of ATTRS
     */
    public final Collection<FileAttribute> getAttributes() {
        return unmodifiableCollection(attributes);
    }

    /**
     * 获取文件对象的Hash。
     *
     * @return 文件对象的Hash。
     */
    public final String getHash() {
        return this.hash;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final int hashCode() {
        return Objects.hash(id);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final boolean equals(
            Object other
    ) {
        if (!(other instanceof FileObject)) return false;
        final FileObject o = (FileObject) other;
        return Objects.equals(this.id, o.id);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final String toString() {
        return "OFile{" + "id:" + id + "}";
    }
}
